package edu.cuit.avatar.common;

import com.mysql.cj.xdevapi.Table;
import edu.cuit.avatar.annotations.IdGenerateStrategy;
import edu.cuit.avatar.annotations.TableField;
import edu.cuit.avatar.annotations.TableId;
import edu.cuit.avatar.annotations.TableName;
import lombok.extern.slf4j.Slf4j;

import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.StringJoiner;

/**
 * @author <a href="mailto:1020zhaodan@163.com">Adan</a>
 * @version 1.0
 * @date 2025/7/26 13:45
 */
@Slf4j
public class DBUtils<T> {
    private JdbcTemplate template = JdbcTemplate.TEMPLATE;

    /**
     * 将实体entity保存进数据库
     * @param entity 实体信息
     * @return 影响行数
     */
    public Serializable save(T entity){
        Serializable idValue = null;
        try {
            //insert into 表名(字段列表) values(字段列表值);
            StringBuilder sb = new StringBuilder("insert into ");
            var annotation = entity.getClass().getAnnotation(TableName.class);
            var tableName = annotation == null ? entity.getClass().getSimpleName() : annotation.value();
            sb.append(tableName);
            StringJoiner fieldJoiner = new StringJoiner(",","(", ")");
            StringJoiner valueJoiner = new StringJoiner(",","(", ")");
            List<Object> params = new ArrayList<>();
            //处理字段列表及对应的参数值
            var beanInfo = Introspector.getBeanInfo(entity.getClass(), Object.class);
            var pds = beanInfo.getPropertyDescriptors();
            for(var pd : pds){
                var getter = pd.getReadMethod();
                var tableField = getter.getAnnotation(TableField.class);
                //获取当前属性所对应数据表字段名
                var fieldName = tableField == null ? StringUtils.mapCamelCaseToUnderscore(pd.getName()) : tableField.name();
                var tableId = getter.getAnnotation(TableId.class);

                if(tableId != null && tableId.strategy() == IdGenerateStrategy.INPUT)
                    idValue = (Serializable) getter.invoke(entity);

                if(tableId == null || tableId.strategy() == IdGenerateStrategy.INPUT){
                    fieldJoiner.add(fieldName);
                    valueJoiner.add("?");
                    //当前字段的值即为当前属性值
                    params.add(getter.invoke(entity));
                }
            }
            sb.append(fieldJoiner).append(" values").append(valueJoiner);
            var sql = sb.toString();
            log.info("insert sql:{}", sql);
            if(idValue == null)
                return template.insert(sql, params.toArray());
            else {
                template.executeUpdate(sql, params.toArray());
                return idValue;
            }

        } catch (IntrospectionException | InvocationTargetException | IllegalAccessException e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }

    public boolean removeById(Serializable id, Class<?> clazz){
        try {
            //delete from tableName where idField = ?;
            var annotation = clazz.getAnnotation(TableName.class);
            var tableName = annotation == null ? clazz.getSimpleName() : annotation.value();
            StringBuilder sb = new StringBuilder("delete from ");
            sb.append(tableName).append(" where ");
            String idField = "";


            var beanInfo = Introspector.getBeanInfo(clazz, Object.class);
            var pds = beanInfo.getPropertyDescriptors();

            for(var pd : pds){
                var getter = pd.getReadMethod();
                var tableId = getter.getAnnotation(TableId.class);
                if(tableId != null){
                    String idFileName = tableId.name();
                    idField = StringUtils.isBlank(idFileName) ? pd.getName() : idFileName;
                    break;
                }
            }
            sb.append(idField).append("=?");
            return template.executeUpdate(sb.toString(), id) == 1;
        } catch (IntrospectionException e) {
            throw new RuntimeException(e);
        }
    }
}
